/*
 ============================================================================
 Name		: CStreamAudioEngine.cpp
 Author	  : 
 Version	 : 1.0
 Copyright   : copyright readever.cn
 2009-2010
 Description : CStreamAudioEngine implementation
 mp3播放引擎实现文件，使用了两个缓冲区交替解码。
 ============================================================================
 */

#include <eikenv.h>             
#include <eikapp.h>
#include <eikdef.h>
#include <e32math.h> 

#include "CStreamAudioEngine.h"
#include "MP3DecodeEngine.h"


CStreamAudioEngine::CStreamAudioEngine()
	:iVolume(KInitialVolume),
	 iVolStep(0),
	 iFileOK(EFalse),
	 iMp3Status(EEngineNotReady),
	 iPlayFile(ETrue),
	 iRepeat(EFalse),
	 imp3Buf(0,0),
	 iStart(EFalse),
	 fm(0),
	 bufx(0)

	{
	// No implementation required
		iMediaOffset = 0;
		iMediaRealSize = 0;
	}

CStreamAudioEngine::~CStreamAudioEngine()
	{
		delete iStream;

		delete [] aa;
		delete imp3;

		fss.Close();
	}

CStreamAudioEngine* CStreamAudioEngine::NewLC()
	{
	CStreamAudioEngine* self = new (ELeave) CStreamAudioEngine();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CStreamAudioEngine* CStreamAudioEngine::NewL()
	{
	CStreamAudioEngine* self = CStreamAudioEngine::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void CStreamAudioEngine::ConstructL()
	{
	 // get the Eikon environment
		iEnv = CEikonEnv::Static();

		imp3=CMP3DecodeEngine::NewL();

		iFileOK = EFalse;
		aa=new (ELeave) TUint16[8192];//缓冲区，存储单帧内容，大小不定，  最好设的足够大，不然会报错

		imp3Buf.Set(aa,8192,8192);


		fss.Connect();
		// create and initialize output stream          
		iStream = CMdaAudioOutputStream::NewL(*this);
		iStream->Open(&iSettings);
	}

void CStreamAudioEngine::MaoscOpenComplete(TInt aError)
	{
		if (aError==KErrNone)
		{
			// set stream properties to 16bit,8KHz mono EChannelsMono EChannelsStereo
			//因为解码后的内容为单声道，所以一定要用TMdaAudioDataSettings::EChannelsMono，另外采样率要和imp3->SetResampleRate设置的一致
			iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate44100Hz, 
				TMdaAudioDataSettings::EChannelsMono);
		
			// set the appropriate volume step. values for the target
			// device are scaled down to get the optimal volume level
			#if defined(__WINS__)
				// for emulator (MaxVolume == 65535)
			iVolStep = iStream->MaxVolume() / KVolSliderLength;
			#else
				// for target device (MaxVolume == 9)
			iVolStep = iStream->MaxVolume() / (KVolSliderLength-1);
			#endif
			iStream->SetVolume(iVolStep * KInitialVolume);        
		
			iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceNone);
		
			iMp3Status = EEngineReady;        
		}
		else        
			ShowErrorMsg(0, aError);
			//ShowErrorMsg(R_WAVEGEN_ERROR_OPENCOMPLETE, aError);
		
		//  PlayL();
	}

void CStreamAudioEngine::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer)
	{
		// if a single file (buffer) is played, return immediately
		
		if(aError==KErrNone || aError==KErrAbort)
		{
			if(iMp3Status==EEngineToPause)
				{
					iMp3Status=EEnginePause;
					iStream->Stop();
					return;
				}
		
			if(iMp3Status==EEnginePause)
				{
				return;
				} 
		
		
			if(iPlayFile )
				{
		
					if(iMp3Status==EEnginePlaying  && iFileOK)
						{
						NextBuffer(aBuffer);
						}
		
					return;
				}
		}
		else
			{
				//  if(iMp3Status!=EEngineReady)
				//  {
				iMp3Status=EEnginePause;
				//   iStream->Stop();
				//  }
				//  User::Invariant();
			}
	}

void CStreamAudioEngine::MaoscPlayComplete(TInt aError)
	{
		if (aError==KErrNone || aError==KErrCancel)
		{
			if(iMp3Status == EEnginePlaying)
				{
					bufx=0;
					iFileOK=EFalse;
					iStart=EFalse;
					iMp3Status = EEngineReady;
			
					imp3->CloseFile();
					iBufList[0].SetLength(0);
					iBufList[1].SetLength(0);
				}
		}
		else
		{
			iMp3Status=EEnginePause;
		//  if(iMp3Status == EEnginePlaying)
		//  {
		//   iMp3Status=EEnginePause;
		//   iStream->Stop();
		//  }
		//  User::Invariant();
		}
	}

void CStreamAudioEngine::PlayL()
    {
		if(iMp3Status == EEngineReady || iMp3Status == EEnginePause)
        {
			iMp3Status = EEnginePlaying;

			if(!iFileOK)
			{
				imp3->OpenFile(fss,tFullFileName, iMediaOffset, iMediaRealSize);
				imp3->SetResampleRate(44100);
				imp3->DecodeStart();
				iFileOK=ETrue;
			}
   
   
			if(!iStart)
			{
				imp3->DecodeOneFrame(imp3Buf);
				iBufList[0].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
				imp3->DecodeOneFrame(imp3Buf);    
				iBufList[1].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
			}
			else
			{
				imp3->DecodeOneFrame(imp3Buf);    
				iBufList[1].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
			}

			iStream->WriteL(iBufList[bufx]);
			if(bufx==0)
				bufx=1;
			else
				bufx=0;
			
			iStart=ETrue;

			if(imp3->GetFilePosition()==imp3->GetFileLength())
			{
				imp3->CloseFile();
			
				if(iRepeat)
				{
					imp3->OpenFile(fss,tFullFileName);
					imp3->SetResampleRate(44100);
					imp3->DecodeStart();
				}
				else
				{
					iFileOK=EFalse;
				}
			}
        }
    }

void CStreamAudioEngine::Pause()
    {
		iMp3Status = EEngineToPause;
    }


void CStreamAudioEngine::StopL()
    {
		bufx=0;
		iFileOK=EFalse;
		iStart=EFalse;
		iMp3Status = EEngineReady;
		
		iStream->Stop();
		imp3->CloseFile();
		iBufList[0].SetLength(0);
		iBufList[1].SetLength(0);
    }

void CStreamAudioEngine::SetRepeat(TBool aRepeat)
 {
	 iRepeat=aRepeat;
 }


void CStreamAudioEngine::OpenL(TFileName aFileName, int mediaoffset, int mediarealsize)
 {
	if(iMp3Status == EEnginePlaying || iMp3Status == EEnginePause)
	{
		StopL();
	}

	//william
	iMediaOffset = mediaoffset;
	iMediaRealSize = mediarealsize;
	
	tFullFileName = aFileName;
	PlayL();
 }


void CStreamAudioEngine::SetVolume(TInt aVol)
	{ 
	iVolume = aVol;
	
	// if value has changed, pass it directly to audiostream object. 
	if((iVolume * iVolStep) != iStream->Volume())        
		iStream->SetVolume(iVolume * iVolStep);
	}

void CStreamAudioEngine::ShowErrorMsg(TInt aResourceBuf, TInt aError)
    {
		TBuf<16> errorNum;
		TBuf<128> rDes;
		errorNum.Num(aError);
		
		iEnv->ReadResource(rDes, aResourceBuf);
		rDes.Append(errorNum);
		
		CEikonEnv::Static()->InfoWinL(_L("error"), rDes);
		//CAknInformationNote* dlg = new(ELeave)CAknInformationNote();
		//dlg->ExecuteLD(rDes); 
    }

void CStreamAudioEngine::NextBuffer(const TDesC8& aBuffer)
    {
	//assume the buffer is already there!
	iStream->WriteL(iBufList[bufx]);
	if(bufx==0)
		bufx=1;
	else
		bufx=0;
	
	if(imp3->GetFilePosition()==imp3->GetFileLength())
	{
		imp3->CloseFile();
		if(iRepeat)
		{
			imp3->OpenFile(fss,tFullFileName);
			imp3->SetResampleRate(44100);
			imp3->DecodeStart();
		}
		else
		{
		iFileOK=EFalse;
		}
	}
	
	
	ASSERT(iBufList[bufx]==aBuffer);
	iBufList[bufx].SetLength(0);
	imp3->DecodeOneFrame(imp3Buf);    
	iBufList[bufx].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
    }

